home *** CD-ROM | disk | FTP | other *** search
/ Power Programmierung / Power-Programmierung (Tewi)(1994).iso / magazine / drdobbs / 1991 / 04 / oliver / fracdraw.c < prev    next >
C/C++ Source or Header  |  1991-01-23  |  30KB  |  715 lines

  1. /***************************************************************** 
  2.    FRACDRAW.C -- Drawing with fractals
  3.    Copyright 1990 by Dick Oliver, R1 Box 5140, Morrisville, VT  05661
  4.    A program for interactive fractal drawing.
  5.    You may copy, modify, and recompile this source code as you please,
  6.    as long as you do not sell it or any product produced from any part of it.
  7.    The author makes no claims as to readability or suitability for a
  8.    particular task, but I'll be happy to give advice and assistance.
  9. *****************************************************************/
  10.  
  11. #include <stdio.h>
  12. #include <stdlib.h>
  13. #include <graph.h>
  14. #include <math.h>
  15. #include <ctype.h>
  16. #include <bios.h>
  17.  
  18. #include "maple.h"   /* Include file for initial template definition */
  19.  
  20. /* Numerical constants */
  21. #define PI 3.141592
  22. #define TWOPI 6.283853
  23. #define HALFPI 1.570796
  24. #define ALMOSTZERO 0.00002
  25. #define MAXSIZE 0.998
  26. #define MAXINT 32767
  27.  
  28. /* Keyboard constants */
  29. #define ENTER 13
  30. #define BACKSPACE 8
  31. #define ESC 27
  32. #define END -'O'
  33. #define HOME -'G'
  34. #define INSERT -'R'
  35. #define DELETE -'S'
  36. #define TAB 9
  37. #define UNTAB -15
  38. #define UP -'H'
  39. #define DN -'P'
  40. #define LT -'K'
  41. #define RT -'M'
  42. #define NULLKEY '^'
  43.  
  44. /* Generic getch() replacement */
  45. #define geta if ((a = getch()) == 0) a = -getch();\
  46.            else if (a > 0) a = toupper(a)
  47.  
  48. /* Main menu */
  49. #define MENUMSG "ACTION    KEY\n"\
  50.              "  Draw     D\n"\
  51.              "  Paint    P\n"\
  52.              "  Both     B\n"\
  53.              " Next Part Tab\n"\
  54.              " NextPoint ~\n"\
  55.              " Insert    Ins\n"\
  56.              " Delete    Del\n"\
  57.              "  Grow     *\n"\
  58.              "  Shrink   /\n"\
  59.              "  Spin     + -\n"\
  60.              "  Skew     ; \'\n"\
  61.              "  Squish   [\n"\
  62.              "  Stretch  ]\n"\
  63.              " Quit      ESC\n\n\n"\
  64.              "     DRAWING\n        WITH\n    FRACTALS\n\n"\
  65.              " (C) 1990 by\n Dick Oliver"
  66.  
  67. #define MENUKEYS {'D', 'P', 'B', TAB, '`', INSERT, DELETE, \
  68.                '*', '/', '+', ';', '[', ']', ESC}
  69. #define MENUWD 15 /* width of menu in characters */
  70. #define NMENUITEMS 14 /* number of menu items */
  71. #define HAND 64 /* size of handle in pixels */
  72. #define MAXPTS 19 /* max. no. of points on seed */
  73. #define MAXTRANS 19 /* max. no. of parts of template */
  74.  
  75. /* template variables:
  76.    spininc is the amount to rotate (in radians) each time spin is picked
  77.    sizeinc is the amount to grow or shrink
  78.    ra, rb, rc, rd, rmx, and rmy are the reverse of the initial tranformation
  79.    fa, fb, fc, and fd are the tranformations computed from
  80.    sizex, sizey, spinx, and spiny
  81.    movex and movey are the translation part of the transformations
  82.    asprat is the aspect ratio (always 1 for VGA)
  83.    fx and fy are used for various temporary storage purposes
  84.    x and y are the points on the seed polygon */
  85.  
  86. float sizeinc = 0.16, spininc = PI / 16,
  87.      ra, rb, rc, rd, rmx, rmy,
  88.      fa[MAXTRANS + 1], fb[MAXTRANS + 1], fc[MAXTRANS + 1], fd[MAXTRANS + 1],
  89.      sizex[MAXTRANS + 1] = {1, SIZEX}, sizey[MAXTRANS + 1] = {1, SIZEY},
  90.      spinx[MAXTRANS + 1] = {0, SPINX}, spiny[MAXTRANS + 1] = {0, SPINY},
  91.      movex[MAXTRANS + 1] = {CENTERX, MOVEX}, 
  92.      movey[MAXTRANS + 1] = {CENTERY, MOVEY},
  93.      asprat, fx, fy, x[MAXPTS] = {SEEDX}, y[MAXPTS] = {SEEDY};
  94.  
  95. /* menu vars */
  96. char a, menukeys[] = MENUKEYS;
  97.  
  98. /* xtop, etc. are the points on the handle
  99.    drawclr is the text and handle color
  100.    xx, yy, midx, and midy are used for various pixel-shuffling operations
  101.    menuitem is the current menu choice
  102.    hand is the size of the handle in pixels
  103.    sk is used to keep track of when to re-sketch the template
  104.    xo and yo are the current template corners for quick erasing
  105.    thispt & thistran are the current point/part
  106.    npts is the number of point, ntrans is the number of parts,
  107.    level is the number of levels of detail to draw or paint
  108.    color determines the color to make each part at each level
  109. */
  110. int xtop, ytop, xctr, yctr, xlft, ylft, xrgt, yrgt,
  111.     drawclr, i, j, xx, yy, midx, midy, menuitem = 0, hand = HAND, sk,
  112.     xo[MAXTRANS + 1][MAXPTS], yo[MAXTRANS + 1][MAXPTS], moveinc = 16,
  113.     thispt = 0, thistran = 0, npts = NPOINTS, ntrans = NTRANS,
  114.     level = NLEVELS - 1, color[MAXTRANS][NLEVELS] = COLOR;
  115.  
  116. /* ptmode means we're in "point" mode rather than "part" mode*/
  117. enum {OFF, ON} ptmode = OFF;
  118.  
  119. /* standard Microsoft video variables */
  120. struct videoconfig vc;
  121. long palette[16] = PALETTE;
  122.  
  123. /* these function prototypes are needed to avoid confusion about parameter
  124.    types (most of the functions aren't prototyped) */
  125. void draw(float a, float b, float c, float d, float mx, float my, int iter);
  126. void warp(float spinxinc, float spinyinc, float sizexinc, float sizeyinc);
  127.  
  128. main()
  129. {
  130.     hello();    /* initialize everything */
  131.     while(1)    /* the main event-processing loop */
  132.     {
  133.         geta;
  134.         switch(a)    /* what shall we do now? */
  135.         {   case BACKSPACE:
  136.         case ' ':
  137.                 /* move ">" to new menu item */
  138.                 _settextposition(menuitem + 2, 1);
  139.                 _outtext(" ");
  140.                 if (a == ' ')
  141.                 {     if (++menuitem == NMENUITEMS) menuitem = 0;
  142.                 }
  143.                 else  if (--menuitem < 0) menuitem = NMENUITEMS - 1;
  144.                 _settextposition(menuitem + 2, 1);
  145.                 _outtext(">");
  146.                 break;
  147.             case ENTER:            /* pick a menu item */
  148.                 ungetch(menukeys[menuitem]);
  149.                 break;
  150.             default:
  151.         sk = 0;
  152.                 switch(a)
  153.                 {   case LT:
  154.                     case RT:
  155.                     case DN:
  156.                     case UP:
  157.                         /* move a point or part of the template */
  158.                         xx = 0, yy = 0;
  159.                         switch (a)
  160.                         {   case LT:      xx = -moveinc;               break;
  161.                             case RT:      xx = moveinc;                break;
  162.                             case UP:      yy = -moveinc;               break;
  163.                             case DN:      yy = moveinc;                break;
  164.                         }
  165.                         if (!ptmode && (thistran == 0))
  166.                             *movex += xx, *movey += yy;
  167.                         else
  168.                         {   if (ptmode)
  169.                             {   x[thispt] += xx * ra + yy * rb;
  170.                                 y[thispt] += xx * rc + yy * rd;
  171.                             }
  172.                             else movex[thistran] += xx * ra + yy * rb,
  173.                                  movey[thistran] += xx * rc + yy * rd;
  174.                         }
  175.                         break;
  176.                     case '/':          /* Shrink */
  177.                         if (ptmode)
  178.                         {    fx = 1 / (sizeinc + 1);
  179.                             warp(0.0, 0.0, fx, fx);
  180.                         }
  181.                         else
  182.                         {   if ((sizex[thistran] /= sizeinc + 1) == 0)
  183.                                 sizex[thistran] = ALMOSTZERO;
  184.                             if ((sizey[thistran] /= sizeinc + 1) == 0)
  185.                                 sizey[thistran] = ALMOSTZERO;
  186.                             computef(thistran);
  187.                         }
  188.                         break;
  189.                     case '*':            /* Grow */
  190.                          if (ptmode) warp(0.0, 0.0,sizeinc+1, sizeinc+1);
  191.                         else
  192.                         {   if (((sizex[thistran] *= sizeinc + 1)
  193.                                  > MAXSIZE)
  194.                                 && (thistran > 0))
  195.                                     sizex[thistran] = MAXSIZE;
  196.                             if (((sizey[thistran] *= sizeinc + 1)
  197.                                  > MAXSIZE)
  198.                                 && (thistran > 0))
  199.                                     sizey[thistran] = MAXSIZE;
  200.                             computef(thistran);
  201.                         }
  202.                         break;
  203.                     case '[':         /* Squish x-axis */
  204.                         if (ptmode) warp(0.0, 0.0, 1/(sizeinc + 1), 1.0);
  205.                         else
  206.                         {    if ((sizex[thistran] /= (sizeinc + 1)) == 0)
  207.                                 sizex[thistran] = ALMOSTZERO;
  208.                             computef(thistran);
  209.                         }
  210.                         break;
  211.                     case ']':    /* Stretch x-axis */
  212.                         if (ptmode) warp(0.0, 0.0, sizeinc + 1, 1.0);
  213.                         else
  214.                         {    if (((sizex[thistran] *= sizeinc + 1)
  215.                                  > MAXSIZE)
  216.                                 && (thistran > 0))
  217.                                     sizex[thistran] = MAXSIZE;
  218.                             computef(thistran);
  219.                         }
  220.                         break;
  221.                     case '-':      /* Spin counter-clockwise */
  222.                         if (ptmode) warp(-spininc, -spininc, 1.0, 1.0);
  223.                         else
  224.                         {   if ((spinx[thistran] -= spininc) < 0)
  225.                                 spinx[thistran] += TWOPI;
  226.                             if ((spiny[thistran] -= spininc) < 0)
  227.                                 spiny[thistran] += TWOPI;
  228.                             computef(thistran);
  229.                         }
  230.                         break;
  231.                     case '+':     /* Spin clockwise */
  232.                         if (ptmode) warp(spininc, spininc, 1.0, 1.0);
  233.                         else
  234.                         {   if ((spinx[thistran] += spininc) >= TWOPI)
  235.                                 spinx[thistran] -= TWOPI;
  236.                             if ((spiny[thistran] += spininc) >= TWOPI)
  237.                                 spiny[thistran] -= TWOPI;
  238.                             computef(thistran);
  239.                         }
  240.                         break;
  241.                     case ';':     /* Skew x-axis counter-clockwise */
  242.                         if (ptmode) warp(spininc, 0.0, 1.0, 1.0);
  243.                         else
  244.                         {   if ((spinx[thistran] += spininc) >= TWOPI)
  245.                                 spinx[thistran] -= TWOPI;
  246.                             computef(thistran);
  247.                         }
  248.                         break;
  249.                     case '\'':   /* Skew x-axis clockwise */
  250.                         if (ptmode) warp(-spininc, 0.0, 1.0, 1.0);
  251.                         else
  252.                         {   if ((spinx[thistran] -= spininc) < 0)
  253.                                 spinx[thistran] += TWOPI;
  254.                             computef(thistran);
  255.                         }
  256.                         break;
  257.                     case '`':    /* NextPoint */
  258.                         if (ptmode) ++thispt;
  259.                         else ptmode = ON, thistran = 0;
  260.                         if (thispt >= npts) thispt = 0;
  261.                         break;
  262.                     default:
  263.                         switch(a)
  264.                         {   case TAB: /* Next part */
  265.                                 if (ptmode)
  266.                                 {    ptmode = OFF;
  267.                                      midpoint();
  268.                                 }
  269.                                 else
  270.                                 {    if (++thistran > ntrans) thistran = 0;
  271.                                 }
  272.                                 break;
  273.                             case 'D':
  274.                             case 'P':
  275.                             case 'B':   /* Draw and/or Paint */
  276.                                 _clearscreen(_GCLEARSCREEN);
  277.                                 _setcliprgn(0, 0,
  278.                                            vc.numxpixels - 1,
  279.                                            vc.numypixels - 1);
  280.                                 _setcolor(**color);
  281.                                 if ((a == 'D') || (a == 'B'))
  282.                                     draw(*fa, *fb, *fc, *fd, 
  283.                          *movex, *movey, level);
  284.                                 if ((a == 'P') || (a == 'B')) paint();
  285.                                 printf("\7");
  286.                                 getch();
  287.                                 _clearscreen(_GCLEARSCREEN);
  288.                                 printmenu();
  289.                                 break;
  290.                             case ESC:   /* Quit */
  291.                                 _setvideomode(_DEFAULTMODE);
  292.                                 printf("Seeyalater!");
  293.                                 exit(0);
  294.                             case INSERT:  /* Insert a point or part */
  295.                                 if (ptmode)
  296.                                 {   if (npts < MAXPTS)
  297.                                     {   erase();
  298.                                         ++npts;
  299.                                         for (i = npts - 1; i > thispt; i--)
  300.                                             x[i] = x[i - 1],
  301.                                             y[i] = y[i - 1];
  302.                                         if (thispt > 0)
  303.                                             xx = x[thispt - 1],
  304.                                             yy = y[thispt - 1];
  305.                                         else xx = x[npts - 1],
  306.                                             yy = y[npts - 1];
  307.                                         if ((xx == x[thispt]) &&
  308.                                             (yy == y[thispt]))
  309.                                             x[thispt] += moveinc,
  310.                                             y[thispt] += moveinc;
  311.                                         else x[thispt] =
  312.                                                 (xx + x[thispt]) / 2,
  313.                                             y[thispt] =
  314.                                                 (yy + y[thispt]) / 2;
  315.                                     }
  316.                                     else printf("\7");
  317.                                 }
  318.                                 else
  319.                                 {   if ((ntrans < MAXTRANS) && (ntrans > 0))
  320.                                     {   ++ntrans;
  321.                                         for (i = ntrans; i > thistran; i--)
  322.                                         {   if (i > 1)
  323.                                             {   movex[i] = movex[i - 1];
  324.                                                 movey[i] = movey[i - 1];
  325.                                                 spinx[i] = spinx[i - 1];
  326.                                                 spiny[i] = spiny[i - 1];
  327.                                                 sizex[i] = sizex[i - 1];
  328.                                                 sizey[i] = sizey[i - 1];
  329.                                                 for (j = 0; j < NLEVELS;
  330.                                                     j++)
  331.                                                     color[i - 1][j] =
  332.                                                         color[i - 2][j];
  333.                                                 fa[i] = fa[i - 1];
  334.                                                 fb[i] = fb[i - 1];
  335.                                                 fc[i] = fc[i - 1];
  336.                                                 fd[i] = fd[i - 1];
  337.                                             }
  338.                                             else
  339.                                             {   spinx[1] = 0;
  340.                                                 spiny[1] = 0;
  341.                                                 sizex[1] = sizey[1];
  342.                                                 computef(1);
  343.                                             }
  344.                                         }
  345.                                         if (thistran == 0) thistran = 1,i = 1;
  346.                                         if (thistran > 1) j = thistran - 1;
  347.                                         else j = ntrans;
  348.                                         if ((movex[i] == movex[j]) &&
  349.                                             (movey[i] == movey[j]))
  350.                                             movex[i] += moveinc,
  351.                                             movey[i] += moveinc;
  352.                                         else movex[i] =
  353.                                                 (movex[i] + movex[j]) / 2,
  354.                                             movey[i] =
  355.                                                 (movey[i] + movey[j]) / 2;
  356.                                     }
  357.                                     else
  358.                                     {   if (ntrans == 0) thistran = ++ntrans;
  359.                                         else printf("\7");
  360.                                     }
  361.                                 }
  362.                                 break;
  363.                             case DELETE:   /* Delete a point or part */
  364.                                 erase();
  365.                                 if (ptmode)
  366.                                 {   if (npts > 1)
  367.                                     {   if (thispt == --npts) --thispt;
  368.                                         else for (i = thispt; i < npts; i++)
  369.                                                 x[i] = x[i + 1],
  370.                                                 y[i] = y[i + 1];
  371.                                     }
  372.                                     else printf("\7");
  373.                                 }
  374.                                 else
  375.                                 {   if (ntrans > 0)
  376.                                     {   --ntrans;
  377.                                     }
  378.                                     else printf("\7");
  379.                                     if (ntrans > 0)
  380.                                     {   if (thistran == 0) thistran = 1;
  381.                                         else
  382.                                             for (i = thistran;
  383.                                                 i <= ntrans; i++)
  384.                                             {   movex[i] = movex[i + 1];
  385.                                                 movey[i] = movey[i + 1];
  386.                                                 spinx[i] = spinx[i + 1];
  387.                                                 spiny[i] = spiny[i + 1];
  388.                                                 sizex[i] = sizex[i + 1];
  389.                                                 sizey[i] = sizey[i + 1];
  390.                                                 for (j = 0; j < NLEVELS;
  391.                                                     j++)
  392.                                                     color[i - 1][j] =
  393.                                                         color[i][j];
  394.                                                 fa[i] = fa[i + 1];
  395.                                                 fb[i] = fb[i + 1];
  396.                                                 fc[i] = fc[i + 1];
  397.                                                 fd[i] = fd[i + 1];
  398.                                             }
  399.                                     }
  400.                                     if (thistran > ntrans) --thistran;
  401.                                 }
  402.                         }
  403.                         sk = 1;
  404.                 }
  405.                 erase();
  406.                 sketch(sk);
  407.         }
  408.     }
  409. }
  410. /* midpoint() -- find the center of the seed */
  411. midpoint()      
  412. {   int xx, yy;
  413.     midx = 0, midy = 0;
  414.     for (i = 0; i < npts; i++) midx += x[i], midy += y[i];
  415.     midx /= npts, midy /= npts;
  416.     for (i = 0; i < npts; i++) x[i] -= midx, y[i] -= midy;
  417.     for (i = 1; i <= ntrans; i++)
  418.     {   xx = midx * fa[i] + midy * fb[i];
  419.         yy = midx * fc[i] + midy * fd[i];
  420.         movex[i] -= midx - xx;
  421.         movey[i] -= midy - yy;
  422.     }
  423.     xx = midx * *fa + midy * *fb,
  424.     yy = midx * *fc + midy * *fd;
  425.     *movex += xx,
  426.     *movey += yy;
  427. }
  428.  
  429. /* compute the affine transformations expressed by the template */
  430. computef(int i)
  431. {   fa[i] =  sizex[i] * cos(spinx[i]);
  432.     fb[i] = -sizey[i] * sin(spiny[i]);
  433.     fc[i] =  sizex[i] * sin(spinx[i]);
  434.     fd[i] =  sizey[i] * cos(spiny[i]);
  435.     if (i == 0)
  436.     {   if ((fx = *fa * *fd - *fb * *fc) == 0) fx = 0.001;
  437.         ra = *fd / fx;
  438.         rb = - *fb / fx;
  439.         rc = - *fc / fx;
  440.         rd = *fa / fx;
  441.     }
  442. }
  443.  
  444. /* warp the seed shape  (used to skew, squish, and stretch) */
  445. void warp(float spinxinc, float spinyinc, float sizexinc, float sizeyinc)
  446. {   float a, b, c, d, dsizex, dsizey, dspinx, dspiny;
  447.     dspinx = spinxinc + *spinx;
  448.     dspiny = spinyinc + *spiny;
  449.     dsizex = sizexinc * *sizex;
  450.     dsizey = sizeyinc * *sizey;
  451.     a =  cos(dspinx) * dsizex;
  452.     b = -sin(dspiny) * dsizey;
  453.     c =  sin(dspinx) * dsizex;
  454.     d =  cos(dspiny) * dsizey;
  455.     for (i = 0; i < MAXPTS; i++)
  456.     {   fx = x[i] * a + y[i] * b;
  457.         fy = x[i] * c + y[i] * d;
  458.         x[i] = fx * ra + fy * rb;
  459.         y[i] = fx * rc + fy * rd;
  460.     }
  461. }
  462.  
  463. /* sketch() -- sketch the template and handle
  464.    Note that the handle shows not only which part you are on,
  465.    but also the relative size and orientation of both axes.
  466. */
  467. sketch(int all)
  468. {   int i, j, x1, y1, inc, tran0 = 0;
  469.     float x2, y2, a, b, c, d, mx, my;
  470.     inc = hand;
  471.     if (ptmode)
  472.     {   tran0 = 1;
  473.         inc *= *sizey / 2;
  474.         fx = x[thispt],  fy = y[thispt];
  475.         x1 = fx * *fa + fy * *fb + *movex;
  476.         y1 = fx * *fc + fy * *fd + *movey;
  477.         xctr = x1, yctr = (y1 + inc) * asprat;
  478.         xtop = x1, ytop = (y1 - inc) * asprat;
  479.         y1 *= asprat;
  480.         xlft = x1 - inc, ylft = y1;
  481.         xrgt = x1 + inc, yrgt = y1;
  482.     }
  483.     else
  484.     {   if (thistran == 0) x1 = 0, y1 = 0, tran0 = 1;
  485.         else x1 = movex[thistran], y1 = movey[thistran];
  486.         if (tran0) fx = x1, fy = y1 - inc;
  487.         else fx = x1 - inc * fb[thistran],
  488.             fy = y1 - inc * fd[thistran];
  489.         xtop = fx * *fa + fy * *fb + *movex;
  490.         ytop = (fx * *fc + fy * *fd + *movey) * asprat;
  491.         xctr = x1 * *fa + y1 * *fb + *movex;
  492.         yctr = (x1 * *fc + y1 * *fd + *movey) * asprat;
  493.         inc /= 2;
  494.         if (tran0) fx = x1 - inc, fy = y1;
  495.         else fx = x1 - inc * fa[thistran],
  496.             fy = y1 - inc * fc[thistran];
  497.         xlft = fx * *fa + fy * *fb + *movex;
  498.         ylft = (fx * *fc + fy * *fd + *movey) * asprat;
  499.         if (tran0) fx = x1 + inc, fy = y1;
  500.         else fx = x1 + inc * fa[thistran],
  501.             fy = y1 + inc * fc[thistran];
  502.         xrgt = fx * *fa + fy * *fb + *movex;
  503.         yrgt = (fx * *fc + fy * *fd + *movey) * asprat;
  504.     }
  505.     _setcolor(**color);
  506.     for (j = 0; j < npts; j++)
  507.     {   x1 = x[j] * *fa + y[j] * *fb + *movex;
  508.         y1 = (x[j] * *fc + y[j] * *fd + *movey) * asprat;
  509.         (*xo)[j] = x1, (*yo)[j] = y1;
  510.         if (j == 0) _moveto(x1, y1);
  511.         else _lineto(x1, y1);
  512.     }
  513.     _lineto(**xo, **yo);
  514.     for (i = 1; i <= ntrans; i++)
  515.     {   if ((thistran == 0) || (i == thistran) || (all))
  516.         {   _setcolor(color[i - 1][level]);
  517.             a = fa[i] * *fa + fc[i] * *fb;
  518.             b = fb[i] * *fa + fd[i] * *fb;
  519.             c = fa[i] * *fc + fc[i] * *fd;
  520.             d = fb[i] * *fc + fd[i] * *fd;
  521.             mx = movex[i] * *fa + movey[i] * *fb + *movex;
  522.             my = movex[i] * *fc + movey[i] * *fd + *movey;
  523.             for (j = 0; j < npts; j++)
  524.             {   x1 = a * x[j] + b * y[j] + mx;
  525.                 y1 = (c * x[j] + d * y[j] + my) * asprat;
  526.                 if (j == 0) _moveto(x1, y1);
  527.                 else _lineto(x1, y1);
  528.                 xo[i][j] = x1, yo[i][j] = y1;
  529.             }
  530.             _lineto(*(xo[i]), *(yo[i]));
  531.         }
  532.     }
  533.     _setcolor(drawclr);
  534.     _moveto(xtop, ytop);
  535.     _lineto(xctr, yctr);
  536.     _moveto(xlft, ylft);
  537.     _lineto(xrgt, yrgt);
  538. }
  539.  
  540. /* erase the template */
  541.  
  542. erase()
  543. {   _setcolor(0);
  544.     _moveto(**xo, **yo);
  545.     for (i = 1; i < npts; i++) _lineto((*xo)[i], (*yo)[i]);
  546.     _lineto(**xo, **yo);
  547.     for (i = 1; i <= ntrans; i++)
  548.     {   if ((thistran == 0) || (i == thistran))
  549.         {   _moveto(*(xo[i]), *(yo[i]));
  550.             for (j = 0; j < npts; j++) _lineto(xo[i][j], yo[i][j]);
  551.             _lineto(*(xo[i]), *(yo[i]));
  552.         }
  553.     }
  554.     _moveto(xtop, ytop);
  555.     _lineto(xctr, yctr);
  556.     _moveto(xlft, ylft);
  557.     _lineto(xrgt, yrgt);
  558. }
  559.  
  560. /* This function uses the "Chaos Game", or "random iteration" algorithm
  561.    to paint the "infinite-level" fractal on the screen.
  562. */
  563.  
  564. paint()
  565. {   int i, j, p[MAXTRANS], tc, tp, ci[NLEVELS], cc = 0, mx, my;
  566.     unsigned long ct = COUNT;
  567.     float x1 = 0.0, y1 = 0.0, x2, y2 = 0, sx[MAXTRANS], sy[MAXTRANS];
  568.     mx = *movex, my = *movey;
  569.  
  570.     /* First, we need to compute the relative area of each part of the
  571.        template.  This is done by comparing the size of the determinants
  572.        of the matrix (a,b,c,d).  These weights are then used to decide
  573.        how often to visit each part--big parts get more visits than small
  574.        ones, giving the overall fractal an even density.
  575.     */
  576.  
  577.     for (i = 1; i <= ntrans; i++)
  578.         y2 += (sx[i - 1] =
  579.                 fabs(fa[i] * fd[i] - fb[i] * fc[i]));
  580.     if (y2 == 0) y2 = 0.01;
  581.     x2 = MAXINT / y2;
  582.     j = 0;
  583.     for (i = 0; i < ntrans; i++)
  584.     {   if ((xx = sx[i] * x2) == 0) xx = 1;
  585.         p[i] = (j += xx);
  586.     }
  587.  
  588.     /* We skip the first eight points on our journey, because it may take
  589.        that long to settle down from wherever we started onto the fractal.
  590.     */
  591.  
  592.     for (j = 0; j < 8; j++)
  593.     {   i = rand() % ntrans + 1;
  594.         x2 = x1 * fa[i] + y1 * fb[i] + movex[i];
  595.         y2 = x1 * fc[i] + y1 * fd[i] + movey[i];
  596.         x1 = x2, y1 = y2;
  597.         ci[cc] = i;
  598.         if (++cc == level) cc = 0;
  599.     }
  600.  
  601.     /* Now we put it on the screen.  The cc, tc, and ci variables are used
  602.        to determine coloring.  At each iteration, we choose a level at
  603.        random out of all the levels we will be coloring.  We then find the
  604.        color for that level based on which part was "visited" that many
  605.        iterations ago.  How does this work?  Each iteration of the orbit
  606.        goes from a point on the "whole" to a point on a "part".  Therefore,
  607.        if we were in part #3 one iteration ago, we are now in a level 1
  608.        reflection of part #3 within the current part.  If we were at part #5
  609.        two cycles ago, we are now painting a point within a level 2
  610.        reflection of part #5, and so on.  */
  611.  
  612.     while(!kbhit() && (--ct != 0))
  613.     {   j = rand();
  614.         for (i = 0; i < ntrans; i++) if (j < p[i]) break;
  615.         i++;
  616.         x2 = x1 * fa[i] + y1 * fb[i] + movex[i];
  617.         y2 = x1 * fc[i] + y1 * fd[i] + movey[i];
  618.         x1 = x2, y1 = y2;
  619.         ci[cc] = i - 1;
  620.         j = rand() % level;
  621.         if ((i = cc - j) < 0) i += level;
  622.         if ((tc = color[ci[i]][j + 1]) > 0)
  623.         {   _setcolor(tc);
  624.             _setpixel((int) (x2 * *fa + y2 * *fb + mx),
  625.                     (int) ((x2 * *fc + y2 * *fd + my) * asprat));
  626.         }
  627.         if (++cc == level) cc = 0;
  628.     }
  629. }
  630.  
  631. /* This function uses the "successive approximation" algorithm to draw
  632.    the fractal.
  633. */
  634.  
  635. void draw(float a, float b, float c, float d, float mx, float my, int iter)
  636. {   int i;
  637.  
  638.     /* When we start drawing, iter is the number of levels to draw.
  639.        Each time we go down one level, we decrement iter.
  640.     */
  641.  
  642.     iter--;
  643.  
  644.     /* If user hits ESC, pass that keypress up through the recursive
  645.        calls until we get back to the main procedure.
  646.     */
  647.  
  648.     if (kbhit() && (getch() == ESC))
  649.     {   ungetch(ESC);
  650.         return;
  651.     }
  652.  
  653.     /*  Draw a reflection of the seed polygon using the current
  654.         transformation */
  655.  
  656.     for (i = 0; i < npts; i++)
  657.     {    fx = x[i] * a + y[i] * b + mx;
  658.          fy = x[i] * c + y[i] * d + my;
  659.          if (i == 0)
  660.          {    xx = fx, yy = fy;
  661.               _moveto((int) fx, (int) (fy * asprat));
  662.          }
  663.          else _lineto((int) fx, (int) (fy * asprat));
  664.     }
  665.     _lineto((int) xx, (int) (yy * asprat));
  666.  
  667.     /* If iter has counted all the way down to zero, don't draw the next
  668.        deepest level, but back out one level instead */
  669.  
  670.     if (iter < 0) return;
  671.     {   /* Call draw recursively for each transformation, drawing the
  672.            next deepest level of each part */
  673.         for (i = 1; i <= ntrans; i++)
  674.         {   _setcolor(color[i - 1][level - iter]);
  675.             draw(fa[i] * a + fc[i] * b,
  676.                  fb[i] * a + fd[i] * b,
  677.                  fa[i] * c + fc[i] * d,
  678.                  fb[i] * c + fd[i] * d,
  679.                  a * movex[i] + b * movey[i] + mx,
  680.                  c * movex[i] + d * movey[i] + my,
  681.                  iter);
  682.         }
  683.     }
  684. }
  685.  
  686. /* display the menu */
  687. printmenu()
  688. {   _settextwindow(1, vc.numtextcols - MENUWD,
  689.               vc.numtextrows, vc.numtextcols);
  690.     _clearscreen(_GWINDOW);
  691.     _outtext(MENUMSG);
  692.     _settextposition(menuitem + 2, 1);
  693.     _outtext(">");
  694.     _setcliprgn(0, 0, vc.numxpixels - (MENUWD + 1) *
  695.                 (vc.numxpixels / vc.numtextcols) - 1,
  696.                 vc.numypixels - 1);
  697. }
  698.  
  699.  
  700. /* initialize everything */
  701. hello()
  702. {   if (!_setvideomode(_VRES16COLOR))
  703.     {   printf("Can't set video mode.  VGA required.");
  704.     }
  705.     _getvideoconfig(&vc);
  706.     _remapallpalette(palette);
  707.     _wrapon(_GWRAPOFF);
  708.     _clearscreen(_GCLEARSCREEN);
  709.     printmenu();
  710.     asprat = (float) (4 * vc.numypixels) / (float) (3 * vc.numxpixels);
  711.     drawclr = vc.numcolors - 1;
  712.     for (i = 0; i <= ntrans; i++) computef(i);
  713.     sketch(0);
  714. }
  715.